<template>
	<div class="sku-container">
		<div v-if="!disabled" class="sku-check">
			<el-table :data="myAttribute" border class="theme-2">
				<el-table-column label="规格名" align="center" width="120" :resizable="false">
					<template #default="scope">
						<el-input v-model="scope.row.name" />
					</template>
				</el-table-column>
				<el-table-column label="规格值" align="center">
					<template #default="scope">
						<template v-if="scope.$index">
							<!-- <el-checkbox
                v-for="(item2, index2) in scope.row.item"
                :key="index2"
                v-model="item2.checked"
                :label="item2.name"
              /> -->
							<el-tag
								v-for="(item2, index2) in scope.row.item"
								:key="index2"
								closable
								:disable-transitions="false"
								size="medium"
								@close="onDeleteAttributeItem(scope.$index, index2)"
							>
								{{ item2.name }}
							</el-tag>
						</template>
						<template v-else>
							<div v-for="(item2, index2) in scope.row.item" :key="index2" class="img_sku-item">
								<!-- <el-checkbox v-model="item2.checked" :label="item2.name" /> -->
								<el-tag closable :disable-transitions="false" size="medium" @close="onDeleteAttributeItem(scope.$index, index2)">
									{{ item2.name }}
								</el-tag>
								<div class="img_sku-item__upload">
									<div class="arrow"></div>
									<div class="upload-img">
										<el-upload
											:action="uploadImgUrl"
											:headers="headers"
											:show-file-list="false"
											accept="image/jpeg,image/jpg,image/png"
											:on-success="(response) => onUploadSuccess(response, scope.$index, index2)"
											:on-error="onUploadError"
											:before-upload="beforeImagesUpload"
											class="img-uploader"
										>
											<el-image v-if="item2.icon" :src="item2.icon" fit="scale-down" />
											<i v-else class="el-icon-upload uploader-icon"></i>
										</el-upload>
									</div>
								</div>
							</div>
						</template>
					</template>
				</el-table-column>
				<el-table-column label="操作" align="center" width="300">
					<template #default="scope">
						<el-row :gutter="10">
							<el-col :span="18">
								<el-input
									v-model="scope.row.addAttribute"
									placeholder="新增一个规格属性"
									class="add-attr"
									@keyup.enter="onAddAttribute(scope.$index)"
								>
									<template #append>
										<el-button icon="el-icon-plus" @click="onAddAttribute(scope.$index)"> 添加 </el-button>
									</template>
								</el-input>
							</el-col>
							<el-col :span="6">
								<el-button v-if="isdelete && Number(scope.$index)" type="danger" @click="onDeleteAttribute(scope.$index)"> 删除 </el-button>
							</el-col>
						</el-row>
					</template>
				</el-table-column>
			</el-table>
		</div>
		<div class="sku-list">
			<el-form ref="form" :model="form" status-icon inline-message>
				<el-table v-if="form.skuData[0] && form.skuData[0].sku" :data="form.skuData" stripe border highlight-current-row>
					<!-- 考虑到异步加载的情况，如果 attribute 数据先加载完成，则表头会立马展示，效果不理想，故使用emitAttribute 数据，该数据为计算属性，通过 myAttribute 生成，结构与 attribute 一致 -->
					<!-- <el-table-column v-if="emitAttribute.length > 0" type="index" width="50" align="center" :resizable="false" /> -->
					<!-- <el-table-column
						v-for="(attr, index) in emitAttribute"
						:key="`attribute-${index}`"
						:label="attr.name"
						:prop="attr.name"
						align="center"
						:resizable="false"
					/> -->
					<el-table-column label="规格属性" align="center" prop="sku" :resizable="false" />
					<el-table-column v-if="emitAttribute.length" label="图片" align="center" :resizable="false">
						<template #default="scope">
							<el-image v-if="scope.row.icon" :src="scope.row.icon" fit="scale-down" style="width: 50px; height: 50px" />
						</template>
					</el-table-column>
					<el-table-column
						v-for="(item, index) in structure"
						:key="`structure-${index}`"
						:label="item.label"
						:prop="item.name"
						align="center"
						:resizable="false"
						min-width="120px"
					>
						<!-- 自定义表头 -->
						<template #header>
							<span :class="{ required_title: item.required }">
								{{ item.label }}
							</span>
							<el-tooltip v-if="item.tip" effect="dark" :content="item.tip" placement="top">
								<i class="el-icon-info" />
							</el-tooltip>
						</template>
						<!-- 自定义表格内部展示 -->
						<template #default="scope">
							<!-- 增加是 key 是为了保证异步验证不会出现 skuData 数据变化后无法验证的 bug -->
							<el-form-item
								v-if="item.type == 'input'"
								:key="`structure-input-${index}-${scope.row.sku}`"
								:prop="'skuData.' + scope.$index + '.' + item.name"
								:rules="rules[item.name]"
							>
								<el-input v-model="scope.row[item.name]" :placeholder="`请输入${item.label}`" />
							</el-form-item>
							<el-form-item
								v-else-if="item.type == 'slot'"
								:key="`structure-input-${index}-${scope.row.sku}`"
								:prop="'skuData.' + scope.$index + '.' + item.name"
								:rules="rules[item.name]"
							>
								<slot :name="item.name" :$index="scope.$index" :row="scope.row" :column="scope.column" />
							</el-form-item>
						</template>
					</el-table-column>
					<!-- 批量设置，当 sku 数超过 2 个时出现 -->
					<template v-if="isBatch && form.skuData.length > 1" #append>
						<el-table :data="[{}]" :show-header="false">
							<el-table-column :width="attribute.length * 100" align="center" :resizable="false"> 批量设置 </el-table-column>
							<el-table-column
								v-for="(item, index) in structure"
								:key="`batch-structure-${index}`"
								align="center"
								:resizable="false"
								min-width="120px"
							>
								<el-input
									v-if="item.type == 'input' && item.batch != false"
									v-model="batch[item.name]"
									:placeholder="`填写一个${item.label}`"
									@keyup.enter="onBatchSet(item.name)"
								/>
							</el-table-column>
						</el-table>
					</template>
				</el-table>
			</el-form>
		</div>
	</div>
</template>

<script>
import { Session } from '/@/utils/storage';
export default {
	name: 'SkuForm',
	props: {
		/**
		 * 上传的图片服务器地址
		 */
		uploadImgUrl: {
			type: String,
			default: `${import.meta.env.VITE_API_URL}/admin/upload_gooods_specs_icon`,
		},
		/**
		 * 原始规格数据
		 * sourceAttribute: [
		 *   { name: '颜色', item: ['黑', '金', '白'] },
		 *   { name: '内存', item: ['16G', '32G'] },
		 *   { name: '运营商', item: ['电信', '移动', '联通'] }
		 * ]
		 */
		sourceAttribute: {
			type: Array,
			default: () => [],
		},
		/**
		 * 已使用的规格数据，用于复原数据，支持.sync修饰符
		 * attribute: [
		 *   { name: '颜色', item: ['黑'] },
		 *   { name: '运营商', item: ['电信', '移动', '联通'] }
		 * ]
		 */
		attribute: {
			type: Array,
			default: () => [],
		},
		/**
		 * 用于复原sku数据，支持.sync修饰符
		 * sku: [
		 *   { sku: '黑;电信', price: 1, stock: 1 },
		 *   { sku: '黑;移动', price: 2, stock: 2 },
		 *   { sku: '黑;联通', price: 3, stock: 3 }
		 * ]
		 */
		sku: {
			type: Array,
			default: () => [],
		},
		/**
		 * 表格结构，注意name字段，用于输出sku数据
		 * structure: [
		 *   { name: "price", type: "input", label: "价格" },
		 *   { name: "stock", type: "input", label: "库存" },
		 * ]
		 */
		structure: {
			type: Array,
			default: () => [],
		},
		// sku 字段分隔符
		separator: {
			type: String,
			default: '_',
		},
		// 无规格的 sku
		emptySku: {
			type: String,
			default: '',
		},
		// 是否显示 sku 选择栏
		disabled: {
			type: Boolean,
			default: false,
		},
		// 主题风格
		theme: {
			type: Number,
			default: 1,
		},
		// 是否开启异步加载
		async: {
			type: Boolean,
			default: false,
		},
		// 是否开启删除
		isdelete: {
			type: Boolean,
			default: false,
		},
	},
	data() {
		return {
			headers: {
				token: Session.get('token'),
			},
			isInit: false,
			myAttribute: [],
			form: {
				skuData: [],
			},
			batch: {},
		};
	},
	computed: {
		rules() {
			// 重新生成验证规则
			let rules = {};
			this.structure.forEach((v) => {
				if (v.type == 'input') {
					rules[v.name] = [];
					if (v.required) {
						rules[v.name].push({
							required: true,
							message: `${v.label}不能为空`,
							trigger: 'blur',
						});
					}
					if (v.validate) {
						rules[v.name].push({
							validator: this.customizeValidate,
							trigger: 'blur',
						});
					}
				} else if (v.type == 'slot') {
					rules[v.name] = [];
					if (v.required) {
						rules[v.name].push({
							required: true,
							message: `${v.label}不能为空`,
							trigger: ['change', 'blur'],
						});
					}
					if (v.validate) {
						rules[v.name].push({
							validator: this.customizeValidate,
							trigger: ['change', 'blur'],
						});
					}
				}
			});
			return rules;
		},
		isBatch() {
			return this.structure.some((item) => {
				return item.type == 'input' && item.batch != false;
			});
		},
		// 将 myAttribute 数据还原会 attribute 数据的结构，用于更新 attribute
		emitAttribute() {
			let attribute = [];
			this.myAttribute.forEach((v1, index) => {
				const obj = {
					name: v1.name,
					item: [],
				};
				if (Number(index)) {
					v1.item.forEach((v2) => {
						if (v2.checked) {
							obj.item.push({ name: v2.name });
						}
					});
				} else {
					v1.item.forEach((v2) => {
						if (v2.checked) {
							obj.item.push({ name: v2.name, icon: v2.icon });
						}
					});
				}
				if (obj.item.length !== 0) {
					attribute.push(obj);
				}
			});
			return attribute;
		},
	},
	watch: {
		myAttribute: {
			handler() {
				if (!this.isInit) {
					// 更新父组件
					this.$emit('update:attribute', this.emitAttribute);
				}
				// 解决通过 $emit 更新后无法拿到 attribute 最新数据的问题
				this.$nextTick(() => {
					if (this.attribute.length !== 0) {
						this.combinationAttribute();
					} else {
						this.form.skuData = [];
						const obj = {
							sku: this.emptySku,
							icon: '',
						};
						this.structure.forEach((v) => {
							if (!(v.type == 'slot' && v.skuProperty == false)) {
								obj[v.name] = typeof v.defaultValue != 'undefined' ? v.defaultValue : '';
							}
						});
						this.form.skuData.push(obj);
					}
					this.clearValidate();
				});
			},
			deep: true,
		},
		'form.skuData': {
			handler(newValue, oldValue) {
				if (!this.isInit || (newValue.length == 1 && newValue[0].sku == this.emptySku)) {
					// 如果有老数据，或者 sku 数据为空，则更新父级 sku 数据
					if (oldValue.length || !this.sku.length) {
						// 更新父组件
						const arr = [];
						newValue.forEach((v1) => {
							const obj = {
								sku: v1.sku,
								icon: v1.icon ? v1.icon : '',
							};
							this.structure.forEach((v2) => {
								if (!(v2.type == 'slot' && v2.skuProperty == false)) {
									obj[v2.name] = v1[v2.name] || (typeof v2.defaultValue != 'undefined' ? v2.defaultValue : '');
								}
							});
							arr.push(obj);
						});
						this.$emit('update:sku', arr);
					}
				}
			},
			deep: true,
		},
	},
	mounted() {
		!this.async && this.init();
	},
	methods: {
		init() {
			this.$nextTick(() => {
				this.isInit = true;
				// 初始化 myAttribute
				let myAttribute = [];
				// 根据 sourceAttribute 复原 myAttribute 的结构
				this.sourceAttribute.forEach((v, index) => {
					const temp = {
						name: v.name,
						canAddAttribute: typeof v.canAddAttribute != 'undefined' ? v.canAddAttribute : true,
						addAttribute: '',
						item: [],
					};
					if (Number(index)) {
						v.item.forEach((itemName) => {
							temp.item.push({
								name: itemName.name,
								checked: false,
							});
						});
					} else {
						v.item.forEach((itemName) => {
							temp.item.push({
								name: itemName.name,
								icon: itemName.icon ? itemName.icon : '',
								checked: false,
							});
						});
					}
					myAttribute.push(temp);
				});
				// 根据 attribute 更新 myAttribute
				this.attribute.forEach((attrVal) => {
					myAttribute.forEach((myAttrVal, index) => {
						if (attrVal.name === myAttrVal.name) {
							attrVal.item.forEach((attrName) => {
								if (
									!myAttrVal.item.some((myAttrItem) => {
										if (attrName.name === myAttrItem.name) {
											myAttrItem.checked = true;
										}
										return attrName.name === myAttrItem.name;
									})
								) {
									if (Number(index)) {
										myAttrVal.item.push({
											name: attrName.name,
											checked: true,
										});
									} else {
										myAttrVal.item.push({
											icon: attrName.icon ? attrName.icon : '',
											name: attrName.name,
											checked: true,
										});
									}
								}
							});
						}
					});
				});
				this.myAttribute = myAttribute;
				// 通过 sku 更新 skuData，但因为 skuData 是实时监听 myAttribute 变化并自动生成，而 watch 是在 methods 后执行，所以增加 setTimeout 方法，确保 skuData 生成后在执行下面的代码
				setTimeout(() => {
					this.sku.forEach((skuItem) => {
						this.form.skuData.forEach((skuDataItem) => {
							if (skuItem.sku === skuDataItem.sku) {
								this.structure.forEach((structureItem) => {
									skuDataItem[structureItem.name] = skuItem[structureItem.name];
								});
							}
						});
					});
					this.isInit = false;
				}, 0);
			});
		},
		// 根据 attribute 进行排列组合，生成 skuData 数据
		combinationAttribute(index = 0, dataTemp = []) {
			if (index === 0) {
				for (let i = 0; i < this.attribute[0].item.length; i++) {
					const obj = {
						sku: this.attribute[0].item[i].name,
						[this.attribute[0].name]: this.attribute[0].item[i].name,
						icon: this.attribute[0].item[i].icon ? this.attribute[0].item[i].icon : '',
					};
					this.structure.forEach((v) => {
						if (!(v.type == 'slot' && v.skuProperty == false)) {
							obj[v.name] = typeof v.defaultValue != 'undefined' ? v.defaultValue : '';
						}
					});
					dataTemp.push(obj);
				}
			} else {
				const temp = [];
				for (let i = 0; i < dataTemp.length; i++) {
					for (let j = 0; j < this.attribute[index].item.length; j++) {
						temp.push(JSON.parse(JSON.stringify(dataTemp[i])));
						temp[temp.length - 1][this.attribute[index].name] = this.attribute[index].item[j].name;
						temp[temp.length - 1]['sku'] = [temp[temp.length - 1]['sku'], this.attribute[index].item[j].name].join(this.separator);
					}
				}
				dataTemp = temp;
			}
			if (index !== this.attribute.length - 1) {
				this.combinationAttribute(index + 1, dataTemp);
			} else {
				if (!this.isInit || this.async) {
					// 将原有的 sku 数据和新的 sku 数据比较，相同的 sku 则把原有的 sku 数据覆盖到新的 sku 数据里
					for (let i = 0; i < this.form.skuData.length; i++) {
						for (let j = 0; j < dataTemp.length; j++) {
							if (this.form.skuData[i].sku === dataTemp[j].sku) {
								// dataTemp[j] = this.form.skuData[i];
								// eslint-disable-next-line no-self-assign
								dataTemp[j] = dataTemp[j];
							}
						}
					}
				}
				this.form.skuData = dataTemp;
			}
		},
		// 新增一个规格
		onAddAttribute(index) {
			if (!this.myAttribute[index].name) {
				this.$message.warning('请输入规格名');
				return true;
			}
			this.myAttribute[index].addAttribute = this.myAttribute[index].addAttribute.trim();
			if (this.myAttribute[index].addAttribute !== '') {
				if (!this.myAttribute[index].addAttribute.includes(this.separator)) {
					const flag = this.myAttribute[index].item.some((item) => {
						return item.name === this.myAttribute[index].addAttribute;
					});
					if (!flag) {
						if (Number(index)) {
							this.myAttribute[index].item.push({
								name: this.myAttribute[index].addAttribute,
								checked: true,
							});
						} else {
							this.myAttribute[index].item.push({
								name: this.myAttribute[index].addAttribute,
								icon: '',
								checked: true,
							});
						}
						this.myAttribute[index].addAttribute = '';
					} else {
						this.$message({
							type: 'warning',
							message: '请勿添加相同规格',
						});
					}
				} else {
					this.$message({
						type: 'warning',
						message: `规格里不允许出现「 ${this.separator} 」字符，请检查后重新添加`,
					});
				}
			}
		},
		// 删除该行
		onDeleteAttribute(index) {
			this.myAttribute.splice(index, 1);
		},
		// 删除规格名某项属性
		onDeleteAttributeItem(index1, index2) {
			this.myAttribute[index1].item.splice(index2, 1);
		},
		onBatchSet(type) {
			if (this.batch[type] != '') {
				this.form.skuData.forEach((v) => {
					v[type] = this.batch[type];
				});
				this.batch[type] = '';
				// 批量设置完成后，触发一次当前列的验证
				this.validateFieldByColumns([type], () => {});
			}
		},
		// 自定义输入框验证，通过调用 structure 里的 validate 方法实现，重点是 callback 要带过去
		customizeValidate(rule, value, callback) {
			let [model, index, name] = rule.field.split('.');
			this.structure.forEach((v) => {
				if (v.name == name) {
					v.validate(this.form[model], index, callback);
				}
			});
		},
		// sku 表单验证
		validate(callback) {
			this.$refs['form'].validate((valid) => {
				callback(valid);
			});
		},
		validateFieldByColumns(colums, callback) {
			let props = [];
			this.form.skuData.forEach((v, i) => {
				colums.forEach((v) => {
					props.push(`skuData.${i}.${v}`);
				});
			});
			this.$refs['form'].validateField(props, (valid) => {
				callback(valid);
			});
		},
		validateFieldByRows(index, prop, callback) {
			this.$refs['form'].validateField([`skuData.${index}.${prop}`], (valid) => {
				callback(valid);
			});
		},
		clearValidate() {
			this.$refs['form'].clearValidate();
		},
		// 上传图片
		onUploadSuccess(res, index, index2) {
			this.myAttribute[index].item[index2].icon = res.data.info.show_url;
			this.form.skuData = this.form.skuData.map((item) => {
				return {
					...item,
					icon: item[this.myAttribute[index].name] == this.myAttribute[index].item[index2].name ? res.data.url : item.icon,
				};
			});
			this.loadingUpload.close();
		},
		onUploadError() {
			this.$message({
				type: 'error',
				message: '上传失败',
			});
			this.loadingUpload.close();
		},
		// 上传图片校验
		beforeImagesUpload(file) {
			let types = ['image/jpeg', 'image/png', 'image/jpg'];
			const isJPG = types.includes(file.type);
			const isLt2M = file.size / 1024 / 1024 < 1;
			if (!isJPG) {
				this.$message.warning('只能是 jpeg,png,jpg 格式');
				return isJPG;
			}
			if (!isLt2M) {
				this.$message.warning('上传图片大小不能超过 1M');
				return isLt2M;
			}
			this.loadingUpload = this.$loading({
				lock: true,
				text: '上传中',
				background: 'rgba(0, 0, 0, 0.7)',
			});
		},
	},
};
</script>

<style lang="scss" scoped>
.sku-container {
	::v-deep(.el-card) {
		margin: 10px 0;
		.el-card__header {
			line-height: initial;
			padding: 10px 20px;
		}
		.el-card__body {
			padding: 10px 20px 20px;
		}
	}
	.sku-check {
		.theme-2 {
			border: 1px solid #ebeef5;
			border-bottom: 0;
			margin-bottom: 20px;
			.el-tag {
				margin-right: 10px;
			}
			.img_sku-item {
				display: inline-block;
				margin-right: 30px;
				vertical-align: middle;
				.img_sku-item__upload {
					width: 94px;
					height: 94px;
					margin-top: 6px;
					padding: 4px;
					border: 1px solid #e5e5e5;
					border-radius: 4px;
					background-color: #fff;
					position: relative;
					margin-bottom: 10px;

					.arrow {
						position: absolute;
						width: 0;
						height: 0;
						top: -8px;
						left: 10%;
						border-style: solid;
						border-color: transparent;
						border-left: 5px solid transparent;
						border-right: 5px solid transparent;
						border-bottom: 5px solid #333;

						&::after {
							position: absolute;
							display: block;
							width: 0;
							height: 0;
							top: 0;
							margin-left: -10px;
							border-color: transparent transparent #fff;
							border-style: solid;
							border-width: 0 10px 10px;
							content: '';
						}
					}

					.el-image,
					.img-uploader,
					.uploader-icon {
						width: 84px;
						height: 84px;
					}

					.uploader-icon {
						line-height: 84px;
						font-size: 30px;
					}

					.el-image {
						display: block;
					}
				}
			}
		}
	}
	.sku-name {
		text-align: right;
	}
	.batch-set {
		width: 100%;
		margin-top: 5px;
	}
	.sku-list {
		line-height: initial;
		::v-deep(.el-input__inner) {
			text-align: center;
		}
		::v-deep(.el-table__append-wrapper) {
			overflow: initial;
			.el-table {
				overflow: initial;
				.el-table__body-wrapper {
					overflow: initial;
				}
			}
		}
		::v-deep(.el-form-item) {
			margin-bottom: 0;
			.el-form-item__content {
				line-height: initial;
				.el-form-item__error {
					margin-left: 0;
				}
			}
		}
		.required_title::before {
			content: '*';
			color: #f56c6c;
		}
	}
}
</style>
